/******************************************************************************
* 	Copyright (c) 2007-2008 All rights reserved
*		Asemantics S.r.l
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer. 
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution,
*    if any, must include the following acknowledgment:
*       "This product includes software developed by 
*	 Asemantics S.r.l."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. All advertising materials mentioning features or use of this software
*    must display the following acknowledgement:
*    This product includes software developed by Asemantics S.r.l.
*    the Semantic Web company, Rome, London, Leiden and its contributors. 
*
* 5. Neither the name of the company nor the names of its contributors
*    may be used to endorse or promote products derived from this software
*    without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Author: Andrea Marchesini - baku@asemantics.com
*
******************************************************************************/

#include <log2html.h>
#include <dot.h>

#include <string.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <errno.h>

static void dot_istance (FILE * fl, gint pid, gint pid_parent,
			 gboolean pid_error, gchar * pid_process,
			 gchar * basename);

gboolean
dot (struct data_t *data, struct log_t *log, gchar * basename,
     GError ** error)
{
  FILE *fl;

  gchar *tmp;
  gchar *image;
  gchar *filename;

  gchar *cmd[6];

  GList *list;
  GList *to_quit = NULL;

  struct log_istance_t *istance;

  gint current_pid, current_pid_parent;
  gboolean current_pid_error;
  gchar *current_pid_process;

  tmp = g_strdup_printf ("%s.dot", basename);
  filename = g_build_path (G_DIR_SEPARATOR_S, data->directory, tmp, NULL);
  g_free (tmp);

  if ((fl = g_fopen (filename, "w")) < 0)
    {
      g_set_error (error, log2html_error_quark (), 0,
		   "Error opening the file '%s': %s", filename,
		   strerror (errno));
      return FALSE;
    }

  g_fprintf (fl, "digraph log2html {\n");

  current_pid = current_pid_parent = 0;
  current_pid_error = FALSE;
  current_pid_process = NULL;

  /* Create the list for the last processes */
  for (list = log->istances; list; list = list->next)
    {
      istance = list->data;

      if (istance->type == ISTANCE_BORN)
	to_quit = g_list_prepend (to_quit, istance);
    }

  /* Remove the istance with a child: */
  for (list = log->istances; list; list = list->next)
    {
      istance = list->data;

      if (istance->type == ISTANCE_BORN && istance->born.parent)
	{
	  GList *l;

	  for (l = to_quit; l; l = l->next)
	    {
	      struct log_istance_t *tmp = l->data;

	      if (tmp->pid == istance->born.parent)
		{
		  to_quit = g_list_remove (to_quit, tmp);
		  break;
		}
	    }
	}
    }

  /* Analyze any istance and write the node: */
  for (list = log->istances; list; list = list->next)
    {
      istance = list->data;

      if (!current_pid || current_pid != istance->pid)
	{
	  if (current_pid)
	    dot_istance (fl, current_pid, current_pid_parent,
			 current_pid_error, current_pid_process, basename);

	  current_pid = istance->pid;
	  current_pid_parent = 0;
	  current_pid_error = FALSE;
	  current_pid_process = istance->process;
	}

      switch (istance->type)
	{
	case ISTANCE_BORN:
	  current_pid_parent = istance->born.parent;
	  break;
	case ISTANCE_DIED:
	  break;
	case ISTANCE_WAIT:
	  break;
	default:
	  current_pid_error = TRUE;
	  break;
	}
    }

  if (current_pid)
    dot_istance (fl, current_pid, current_pid_parent, current_pid_error,
		 current_pid_process, basename);

  if (log->startup)
    g_fprintf (fl, "  startup [shape=Mdiamond];\n");

  if (log->quit)
    {
      g_fprintf (fl, "  quit [shape=Mdiamond];\n");

      for (list = to_quit; list; list = list->next)
	{
	  istance = list->data;

	  g_fprintf (fl, "  \"%s_%d\" -> quit;\n", basename, istance->pid);
	}
    }

  g_list_free (to_quit);

  g_fprintf (fl, "\n}\n\n");
  fclose (fl);

  /* Executing the file: */
  tmp = g_strdup_printf ("%s.png", basename);
  image = g_build_path (G_DIR_SEPARATOR_S, data->directory, tmp, NULL);
  g_free (tmp);

  cmd[0] = "dot";
  cmd[1] = "-Tpng";
  cmd[2] = "-o";
  cmd[3] = image;
  cmd[4] = filename;
  cmd[5] = NULL;

  if (g_spawn_sync
      (NULL, cmd, NULL,
       G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL |
       G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, NULL, NULL, NULL,
       error) == FALSE)
    {
      g_free (image);
      g_free (filename);
      return FALSE;
    }

  /* Map file file: */
  cmd[0] = "dot";
  cmd[1] = "-Tcmapx";
  cmd[2] = filename;
  cmd[3] = NULL;

  if (g_spawn_sync
      (NULL, cmd, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL,
       NULL, NULL, &tmp, NULL, NULL, error) == FALSE)
    {
      g_free (image);
      g_free (filename);
      return FALSE;
    }

  /* Save the map: */
  log->map = tmp;

  g_free (image);
  g_free (filename);
  return TRUE;
}

/* WRITE FUNC **************************************************************/
static void
dot_istance (FILE * fl, gint pid, gint pid_parent, gboolean pid_error,
	     gchar * pid_process, gchar * basename)
{
  g_fprintf (fl,
	     "  \"%s_%d\" [href=\"%s_%d.html\", color=%s,label=\"%s\\nPid: %d\"];\n",
	     basename, pid, basename, pid,
	     pid_error == TRUE ? "red" : "green", pid_process, pid);

  if (pid_parent)
    g_fprintf (fl, "  \"%s_%d\" -> \"%s_%d\";\n", basename, pid_parent,
	       basename, pid);
  else
    g_fprintf (fl, "  startup -> \"%s_%d\";\n", basename, pid);
}

/* EOF */
